﻿#region 참조 네임스페이스

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Net;
using System.Text;

#endregion

namespace Skying.Net
{
	/// <summary>
	/// <see cref="System.Net.HttpWebRequest"/> 클래스에 대한 확장 메서드를 제공한다.
	/// </summary>
	public static class HttpWebRequestExtensions
	{
		#region 상수

		/// <summary>
		/// 업로드 시에 사용되는 Request Method 상수를 나타낸다.
		/// </summary>
		private const string _UPLOAD_METHOD = "POST";

		#endregion

		#region 업로드

		/// <summary>
		/// <para>파일을 업로드한다.</para>
		/// <para>이 메서드는 파일을 업로드할 때 다른 파라메터를 전송할 수 있는 방법을 제공한다.</para>
		/// </summary>
		/// <param name="request">
		/// <para>파일을 업로드할 때 사용되는 <see cref="System.Net.HttpWebRequest"/>를 설정한다.</para>
		/// <para>이 메서드의 확장 대상이다.</para>
		/// </param>
		/// <param name="uri">업로드를 요청할 대상 URI을 설정한다.</param>
		/// <param name="parameters">파일 업로드 시에 함께 전송될 파라메터의 이름/값 쌍 목록을 설정한다.</param>
		/// <param name="files">업로드할 파일들의 정보 객체인 <see cref="Skying.Net.HttpWebUploadFile"/> 클래스의 인스턴스 목록을 설정한다.</param>
		/// <returns>웹서버로부터 응답된 결과가 반환된다.</returns>
		public static byte[] Upload(this HttpWebRequest request, string uri, NameValueCollection parameters, IEnumerable<HttpWebUploadFile> files)
		{
			string boundary = string.Format("---------------------------{0}", DateTime.Now.Ticks.ToString("x", NumberFormatInfo.InvariantInfo));

			request.Method = _UPLOAD_METHOD;
			request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);

			boundary = string.Format("--{0}", boundary);

			using (Stream requestStream = request.GetRequestStream())
			{
				foreach (string name in parameters.Keys)
				{
					byte[] buffer = Encoding.ASCII.GetBytes(string.Format("{0}{1}", boundary, Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);

					buffer = Encoding.ASCII.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"{1}{1}", name, Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);

					buffer = Encoding.UTF8.GetBytes(string.Format("{0}{1}", parameters[name], Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);
				}

				foreach (var file in files)
				{
					var buffer = Encoding.ASCII.GetBytes(string.Format("{0}{1}", boundary, Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);

					buffer = Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"{2}", file.ParameterName, file.FileName, Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);

					buffer = Encoding.ASCII.GetBytes(string.Format("Content-Type: {0}{1}{1}", file.ContentType, Environment.NewLine));

					requestStream.Write(buffer, 0, buffer.Length);

					using (Stream stream = File.Open(file.FileName, FileMode.Open))
					{
						stream.CopyTo(requestStream);
					}

					buffer = Encoding.ASCII.GetBytes(Environment.NewLine);

					requestStream.Write(buffer, 0, buffer.Length);
				}

				var boundaryBuffer = Encoding.ASCII.GetBytes(string.Format("{0}--", boundary));

				requestStream.Write(boundaryBuffer, 0, boundaryBuffer.Length);
			}

			using (var response = request.GetResponse())
			{
				using (var responseStream = response.GetResponseStream())
				{
					using (var stream = new MemoryStream())
					{
						responseStream.CopyTo(stream);

						return stream.ToArray();
					}
				}
			}
		}

		#endregion
	}
}